home *** CD-ROM | disk | FTP | other *** search
- ///////////////////////////////////////////////////////////////////////////////
- // FILENAME: eTBookmark.m
- // SUMMARY: Implementation of the "brains" behind eText bookmarks
- // SUPERCLASS: Object
- // INTERFACE: None
- // PROTOCOLS: <Annotation,HTMDSupport,ASCIISupport,LaTeXSupport,Tool,
- // InspectableTarget>
- // AUTHOR: Rohit Khare
- // COPYRIGHT: (c) 1994 California Institure of Technology, eText Project
- ///////////////////////////////////////////////////////////////////////////////
- // IMPLEMENTATION COMMENTS
- // Bookmark creation and destruction are incredibly fragile and complex
- // timelines, what with consistency, integrity, and bindery checking.
- // How does this coordinate with eText to find locations, etc?
- // For HTML conversion, we decided to reduce range-support to point-
- // support for bookmarks by bracketing AnchorTitle with <A NAME...>
- ///////////////////////////////////////////////////////////////////////////////
- // HISTORY
- // 10/30/94: Modified to support <InspectableTarget>
- // 06/18/94: Added HTMDSupport. RK & TRZ
- // 05/08/94: Created. First actual implementation.
- ///////////////////////////////////////////////////////////////////////////////
-
- #import "eTBookmark.h"
- #import "eTPointmark.h"
- #define _eTBookmarkVERSION 10
-
- @implementation eTBookmark
-
- + toolAwake:theApp
- {
- char buf[MAXPATHLEN];
- NXBundle *bundle;
-
- bundle = [NXBundle bundleForClass:[eTBookmark class]];
- if ([bundle getPath:buf forResource:".bmBegin" ofType:"tiff"] ) {
- [[[NXImage alloc] initFromFile:buf] setName:".bmBegin"];
- } else {
- NXLogError("Image not found: .bmBegin");
- }
- if ([bundle getPath:buf forResource:".bmEnd" ofType:"tiff"] ) {
- [[[NXImage alloc] initFromFile:buf] setName:".bmEnd"];
- } else {
- NXLogError("Image not found: .bmEnd");
- }
- if ([bundle getPath:buf forResource:".bmCollapsed" ofType:"tiff"] ) {
- theIcon = [[NXImage alloc] initFromFile:buf];
- [theIcon setName:".bmCollapsed"];
- } else {
- NXLogError("Image not found: .bmCollapsed");
- }
- [theApp registerAnnotation: [eTBookmark class]
- name: "eTBookmark"
- RTFDirective: "eTBookmark"
- menuLabel: "Make Bookmark"
- menuKey: 'B'
- menuIcon: (NXImage *) theIcon];
- [theApp registerAnnotation: [eTBookmarkEnd class]
- name: "eTBookmarkEnd"
- RTFDirective: "eTBookmarkEnd"
- menuLabel: NULL
- menuKey: 0
- menuIcon: (NXImage *) nil];
- [eTPointmark toolAwake:theApp]; //Chaining
- return self;
- }
-
-
- - init
- {
- [super init];
- etContainer = etDoc = theEnd = theText = nil;
- highlighted = collapsed = NO;
- anchorID = 0;
- anchorTitle = NXUniqueString("Untitled");
- condition = NXUniqueString("");
- theIcon = [NXImage findImageNamed:".bmBegin"];
- theTextFieldCell = [[TextFieldCell alloc] initTextCell:"Bookmark"];
- [[theTextFieldCell setBackgroundGray:NX_BLACK] setTextGray:NX_WHITE];
- return self;
- }
-
- - free
- {
- // it's not clear that we can expand: recursively in a Text edit.
- //if (collapsed) NXLogError("AAAAAAAAAAAAAAAAHHHHHHHHHH!!!!!!!!!");
- [[NXApp inspector] inspect:nil];
- [[eTBookmarkBinder new] unregisterBM:self ID:anchorID inDoc:[[etDoc docInfo] docID]];
- [etDoc unregisterNotification:self];
- if (etContainer) etContainer = [etContainer free];
- if (theEnd) theEnd = [theEnd beginDidFree];
- return self = [super free];
- }
-
- - initFromPboard:thePboard inDoc:theDoc linked:(BOOL) linked
- {
- NXSelPt begin, end;
-
- [self init];
- etDoc = theDoc;
- anchorID = [NXApp uniqueID];
- anchorTitle = NXUniqueString([[theDoc docInfo] docTitle]);
- [[eTBookmarkBinder new] registerBM:self ID:anchorID inDoc:[[etDoc docInfo] docID]];
- [etDoc registerNotification:self];
-
- // create bmEnd
- theEnd = [[eTBookmarkEnd alloc] init:self ID:anchorID];
-
- // HIGHLY UNSCRUPULOUS KERNEL VIOLATION!!!!!
- // move sel to end and insert bmEnd into the doc
- theText = [[theDoc docUI] eTextObj];
- [theText getSel:&begin :&end]; // we know the sel exists because
- // etApp checks acceptsAnnotation:
- [theText setSel:end.cp :end.cp];
- [[theText undoManager] disableUndoRegistration];
- [theDoc insertAnnotation:theEnd];
- [[theText undoManager] reenableUndoRegistration];
-
- // now move sel to the beginning and return (we will be inserted there)
- [theText setSel:begin.cp :begin.cp];
- // this provides user feedback; if another bookmark is in the Inspector
- // then this maneuver keeps the bmBrowser updated.
- [self click:self];
- return self;
- }
-
- - calcCellSize:(NXSize *)theSize
- {[theIcon getSize:theSize]; return self;}
- - drawSelf:(const NXRect *)cellFrame inView:view // MARGINALIA HERE!
- {
- NXPoint point; NXCoord l,r,t,b; NXRect rt;
-
- if(!theText) theText = view;
- PSgsave();
- if (highlighted) PSsetgray(NX_LTGRAY);
- else PSsetgray([view backgroundGray]);
- NXRectFill(cellFrame);
- point = cellFrame->origin;
- point.y += cellFrame->size.height;
- [theIcon composite:NX_SOVER toPoint:&point];
-
- // Now we stamp the marginalia note
- // build a rect for the text
- if (theTextFieldCell) {
- NXRun *theRun = [theText runForAnnotation:self];
- rt = *cellFrame;
-
- [theTextFieldCell setFont:theRun->font];
- [theTextFieldCell setStringValue:anchorTitle];
- NX_Y(&rt) += (NX_HEIGHT(&rt) - 18.0);
- NX_HEIGHT(&rt) = 18.0;
- [theText getMarginLeft:&l right:&r top:&t bottom:&b];
- NX_WIDTH(&rt) = (l - 8.0);
- NX_X(&rt) = 4.0;
- [theTextFieldCell drawSelf:&rt inView:view];
- }
- PSgrestore();
- return self;
- }
- - highlight:(const NXRect *)cellFrame inView:view lit:(BOOL)flag
- {
- if (highlighted != flag) {
- highlighted = flag;
- NXHighlightRect(cellFrame);
- }
- return self;
- }
-
- #define mask (NX_LMOUSEUPMASK|NX_LMOUSEDRAGGEDMASK)
- #define Shift(e) (e->flags&(NX_NEXTLSHIFTKEYMASK|NX_NEXTRSHIFTKEYMASK))
- #ifndef abs
- #define abs(x) (((x)<0)? -(x) : (x))
- #endif
-
- int eTBookmark_mouseMoved(NXPoint *o, int n) {
- /* true if mouse moves > n pixels from 'o' */
- NXEvent *e;
- NXPoint p;
- float d;
- do {
- e = [NXApp getNextEvent:mask];
- p = e->location;
- d = abs(p.x-o->x);
- if (d < abs(p.y-o->y)) d = abs(p.y-o->y);
- } while (e->type != NX_LMOUSEUP && d<n);
- *o = p;
- return e->type != NX_LMOUSEUP;
- }
- - (NXDragOperation)draggingSourceOperationMaskForLocal:(BOOL)flag
- {
- return (flag ? NX_DragOperationLink : NX_DragOperationAll);
- }
- - draggedImage:(NXImage *)image endedAt:(NXPoint *)screenPoint deposited:(BOOL)flag
- {
- return self;
- }
- - (BOOL) trackMouse:(NXEvent *)event
- inRect:(const NXRect *)cellFrame
- ofView:controlView
- {
- NXPoint hitPoint, preHitPoint;
- int oldMask;
- NXEvent saveEvent;
- Pasteboard *dragPasteboard;
- NXPoint mouseLocation;
-
- mouseLocation = event->location;
- [controlView convertPoint:&mouseLocation fromView:NULL];
- oldMask = [[controlView window] eventMask];
- [[controlView window] setEventMask:(oldMask|mask)];
- saveEvent = *event;
- preHitPoint = event->location;
- hitPoint = event->location;
-
- if (NXPointInRect(&mouseLocation, cellFrame)) {
- if (event->data.mouse.click == 2)
- [self doubleClick:self];
- else if (event->data.mouse.click == 1) {
- if (eTBookmark_mouseMoved(&hitPoint,4)) {
- NXRect dragRect;
- id theTable;
- char filename[MAXPATHLEN];
- NXPoint imgLoc, offset;
- NXEvent *nextEvent;
-
- theTable = [[NXStringTable alloc] init];
- [theTable insertKey:DOCID value:
- NXCopyStringBuffer([[etDoc docInfo] docIDStr])];
- sprintf(filename,"%x", anchorID);
- [theTable insertKey:ANCHORID value:NXCopyStringBuffer(NXUniqueString(filename))];
- [theTable insertKey:DOCTITLE value:
- NXCopyStringBuffer([[etDoc docInfo] docTitle])];
- [theTable insertKey:ANCHORTITLE value:
- NXCopyStringBuffer(anchorTitle)];
- sprintf(filename, "/tmp/%s.etfLink", anchorTitle);
- [theTable writeToFile:filename];
- theTable = [[theTable empty] free];
-
- dragPasteboard = [Pasteboard newName: NXDragPboard];
- [dragPasteboard declareTypes:&NXFilenamePboardType num:1 owner:nil];
- [dragPasteboard writeType: NXFilenamePboardType data: filename
- length: strlen(filename)];
-
- imgLoc = saveEvent.location;
- [controlView convertPoint:&imgLoc fromView:nil];
- imgLoc.x -= 5;
- imgLoc.y += 5;
-
- nextEvent = [NXApp currentEvent];
- offset.x = nextEvent->location.x - saveEvent.location.x;
- offset.y = nextEvent->location.y - saveEvent.location.y;
-
- [controlView
- dragImage:[NXImage findImageNamed:"NXLinkButton"]
- at:&imgLoc offset:&offset
- event:&saveEvent pasteboard:dragPasteboard
- source:self slideBack: YES];
- } else {
- [self click:self];
- }
- }
- }
- [[controlView window] setEventMask:oldMask];
- return YES;
- }
-
- - readRichText:(NXStream *)stream forView:view
- {
- int i;
- char buf[MAXPATHLEN];
-
- NXScanf(stream, "%d ", &i);
- if (i != _eTBookmarkVERSION) {
- // bad version block.
- NXLogError("eTBookmark found unparseable version %d at position %d",
- i, NXTell(stream));
- return nil;
- }
-
- if (!theText) theText=view;
- NXScanf(stream, "%x ", &anchorID);
-
- NXScanf(stream, "%d", &i); NXGetc(stream); // space-eater
- if (i) NXRead(stream, buf, i);
- buf[i] = 0;
- anchorTitle = NXUniqueString(buf);
-
- NXScanf(stream, "%d", &i); NXGetc(stream); // space-eater
- if (i) NXRead(stream, buf, i);
- buf[i] = 0;
- condition = NXUniqueString(buf);
-
- // Register with the Binder!
- if (!etDoc) etDoc = [view etDoc];
- [[eTBookmarkBinder new] registerBM:self ID:anchorID inDoc:[[etDoc docInfo] docID]];
- [etDoc registerNotification:self];
-
- return self;
- }
- - writeRichText:(NXStream *)stream forView:view
- {
- NXPrintf(stream, "%d %x %d %s %d %s", _eTBookmarkVERSION,anchorID, strlen(anchorTitle), anchorTitle, strlen(condition), condition);
- return self;
- }
- - writeASCII:(NXStream *)stream forView:view
- {
- NXPrintf(stream, "%y\n", anchorTitle);
- return self;
- }
-
- - writeASCIIRef:(NXStream *)stream forView:view
- {
- NXPrintf(stream, "This is anchor ID# %x", anchorID);
- return self;
- }
- - writeHTML:(NXStream *)stream forView:view
- {
- NXPrintf(stream, "<A NAME=\"%x\"><B>%v</B></A>\n", anchorID,anchorTitle);
- return self;
- }
- - writeLaTeX:(NXStream *)stream forView:view
- {
- NXPrintf(stream, "{\\em %w}",anchorTitle);
- return self;
- }
-
- - docWillWrite:etDoc
- {
- if (collapsed){
- int begin;
-
- begin = [theText positionForAnnotation:self];
- [theText setSel:(begin+1) :(begin+1)];
- [etContainer expand:theText];
- reclose = YES;
- }else reclose = NO;
- return self;
- }
-
- - docDidWrite:etDoc
- {
- // collapse back all the previously collapsed ones
- if (reclose) {
- int begin,end;
-
- begin = [theText positionForAnnotation:self];
- end = [theText positionForAnnotation:theEnd];
- if (end == -1) return self;
- [theText setSel:(begin+1) :(end+1)];
- //create a container
- if (!etContainer) etContainer = [[eTextContainer alloc] init];
- [etContainer collapse:theText];
- }
- return self;
- }
-
- - docWillOpen:etDoc
- {
- // consult the userModel and collapse out conditioned bookmarks
- if (condition && *condition && ![[NXApp userModel] boolQuery:condition])
- [self collapse];
- return self;
- }
-
- - setTitle:(const char *) newTitle
- {
- anchorTitle = NXUniqueString(newTitle);
- [[theText superview] display];
- return self;
- }
-
- - setCondition:(const char *) newCondition
- {
- condition = NXUniqueString(newCondition);
- return self;
- }
-
- - collapse
- {
- int begin,end;
-
- begin = [theText positionForAnnotation:self];
- end = [theText positionForAnnotation:theEnd];
- if ((begin == -1) || (end == -1)) return self;
- [theText setSel:(begin+1) :(end+1)];
- [theText scrollSelToVisible];
- //create a container
- if (!etContainer) etContainer = [[eTextContainer alloc] init];
- [etContainer collapse:theText];
- theIcon = [NXImage findImageNamed:".bmCollapsed"];
- collapsed = YES;
- highlighted = NO;
- [[theText superview] display];
- return self;
- }
-
- - expand
- {
- int begin;
-
- begin = [theText positionForAnnotation:self];
- if (begin == -1) {NXBeep(); return self;}
- [theText setSel:(begin+1) :(begin+1)];
- [etContainer expand:theText];
- theIcon = [NXImage findImageNamed:".bmBegin"];
- collapsed = NO;
- highlighted = NO;
- [self highlight:self];
- return self;
- }
-
- - click:sender
- {
- [[NXApp inspector] inspect:self];
- return self;
- }
- - (id <Inspectable>) inspectableDelegate {
- return [[eTBookmarkUI new] setBookmark:self inDoc:[[etDoc docInfo] docID]]; }
-
- - doubleClick:sender
- {
- if (collapsed) [self expand];
- else [self collapse];
- return self;
- }
-
- - (NXAtom)title {return anchorTitle;}
- - (NXAtom)condition {return condition;}
- - (long)id {return anchorID;}
- - setEnd:newEnd {theEnd=newEnd; return self;}
-
- - endDidFree:sender
- {
- // this is the doozie. Suicide?
- theEnd = nil;
- return self;
- }
-
- - highlight:sender
- {
- int begin,end;
-
- if (collapsed) [self expand];
- begin = [theText positionForAnnotation:self];
- if (begin == -1) {NXBeep(); return self;}
- end = [theText positionForAnnotation:theEnd];
- if (end == -1) {
- // find eoparagraph and insert an end there
- end =[theText positionFromLine:([theText lineFromPosition:begin]+1)]-1;
- if (end < begin) end = begin+1;
- // create bmEnd
- theEnd = [[eTBookmarkEnd alloc] init:self ID:anchorID];
- [theText setSel:end:end];
- [etDoc insertAnnotation:theEnd];
- end++;
- }
- //[theText display];
- [theText setSel:(begin) :(end+1)];
- [theText scrollSelToVisible];
- return self;
- }
-
- @end